home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Magnum One
/
Magnum One (Mid-American Digital) (Disc Manufacturing).iso
/
d12
/
v9n08.arc
/
TYPEFAST.ASM
< prev
next >
Wrap
Assembly Source File
|
1990-03-30
|
21KB
|
498 lines
;-----------------------------------------------;
; TYPEFAST * PC Magazine * Michael J. Mefford ;
; Keyboard acceleration for XTs. ;
;-----------------------------------------------;
BIOS_DATA SEGMENT AT 40H
ORG 1AH
BUFFER_HEAD DW ?
BUFFER_TAIL DW ?
ORG 80H
BUFFER_START DW ?
BUFFER_END DW ?
BIOS_DATA ENDS
_TEXT SEGMENT PUBLIC 'CODE'
ASSUME CS:_TEXT
ORG 100H
START: JMP INITIALIZE
; DATA AREA
; ---------
SIGNATURE DB CR,SPACE,SPACE,SPACE,CR,LF
COPYRIGHT DB "TYPEFAST 1.0 (C) 1989 Ziff Communications Co.",CR,LF
PROGRAMMER DB "PC Magazine ",BOX," Michael J. Mefford",CR,LF,LF,"$"
DB CTRL_Z
CR EQU 13
LF EQU 10
CTRL_Z EQU 26
SPACE EQU 32
BOX EQU 254
BELL EQU 7
TRUE EQU 1
FALSE EQU 0
PORT_A EQU 60H
BREAK_CODE EQU 80H
INITIAL_MAX EQU 3
REPEAT_MAX EQU 31
BIOS_INT_9 DW ?,?
BIOS_INT_8 DW ?,?
SCAN_CHAR DW -1
SCAN_CODE DB ?
INIT_DEFAULT EQU INITIAL_MAX
INIT_DELAY DB ?
DELAY DB ?
REPEAT_DEFAULT EQU 2
REPEAT DW ?
REPEAT_CNT DW ?
REPEAT_FLAG DB FALSE
ACTIVE_FLAG DB TRUE
TYPEMATIC DB FALSE
; CODE AREA
; ---------
FASTKEY_INT_9 PROC NEAR
ASSUME DS:NOTHING
PUSH AX ;Preserve some registers.
PUSH BX
PUSH DS
IN AL,PORT_A ;Retrieve scan code.
MOV TYPEMATIC,FALSE ;No typematic while processing.
ASSUME DS:BIOS_DATA ;Point to BIOS data segment.
MOV BX,SEG BIOS_DATA
MOV DS,BX
MOV BX,BUFFER_TAIL ;Retrieve KBD buffer tail.
PUSHF ;Emulate an interrupt.
CALL DWORD PTR BIOS_INT_9 ;Let INT 9 process keystroke.
CMP ACTIVE_FLAG,TRUE ;Are we active?
JNZ INT_9_EXIT ;If no, done here.
CMP BX,BUFFER_TAIL ;Did buffer tail change?
JNZ KEY_PRESS ;If yes, process input.
;------------------------------------------------------------------------;
; Clear the keyboard buffer if key is released and we've been repeating. ;
;------------------------------------------------------------------------;
TEST AL,BREAK_CODE ;Else, was it a key release?
JZ END_TYPEMATIC ;If no, shift key;
AND AL,NOT BREAK_CODE ;Else, strip release bit.
CMP AL,SCAN_CODE ;Is it same as last press?
JNZ INT_9_EXIT ;If no, done here.
END_TYPEMATIC: MOV SCAN_CHAR,-1 ;Else, reset our scan/char code.
CMP REPEAT_FLAG,TRUE ;Have we been stuffing?
JNZ INT_9_EXIT ;If no, done here.
MOV REPEAT_FLAG,FALSE ;Else, reset repeat flag.
MOV BUFFER_HEAD,BX ;Clear keyboard buffer.
JMP SHORT INT_9_EXIT ;Exit.
;----------------------------------------------------------------;
; If key press and same key then continue typematic, else reset. ;
;----------------------------------------------------------------;
KEY_PRESS: MOV SCAN_CODE,AL ;Store the scan code.
MOV AX,[BX] ;Retrieve last scan code.
CMP AX,SCAN_CHAR ;Is it the same as last?
MOV SCAN_CHAR,AX ;Store the character.
JZ TYPEMATIC_ON ;If yes, continue typematic.
MOV BL,INIT_DELAY ;Else, reset the delay.
SHL BL,1
SHL BL,1
ADD BL,4
MOV DELAY,BL
TYPEMATIC_ON: MOV TYPEMATIC,TRUE ;Turn typematic back on.
;------------------------;
INT_9_EXIT: POP DS ;Restore registers.
POP BX
POP AX
IRET
FASTKEY_INT_9 ENDP
;**********************************************;
FASTKEY_INT_8 PROC NEAR
PUSH DS ;Preserve data segment.
ASSUME DS:_TEXT ;Point to our data.
PUSH CS
POP DS
CMP TYPEMATIC,TRUE ;Is typematic active?
JNZ INT_8_EXIT ;If no, done here.
CMP DELAY,0 ;Is delay timed-out?
JZ CK_BUFFER ;If yes, see if we should stuff.
DEC DELAY ;Else, decrement delay.
JMP SHORT INT_8_EXIT ;Exit.
;-----------------------------------------------------------;
; If there is room, stuff the keyboard with last keystroke. ;
;-----------------------------------------------------------;
CK_BUFFER: STI
PUSH AX ;Preserve some more registers.
PUSH BX
PUSH CX
PUSH DI
MOV AX,SCAN_CHAR ;Retrieve last scan/char code.
MOV CX,REPEAT_CNT ;Retrieve no. of times to repeat.
ASSUME DS:BIOS_DATA ;Point to BIOS data area.
MOV BX,SEG BIOS_DATA
MOV DS,BX
CLI ;No interrupts.
NEXT_STUFF: ROL CS:REPEAT,1 ;Rotate left one.
JNC CK_REPEAT
STUFF_KBD: MOV BX,BUFFER_TAIL ;Retrieve buffer tail.
MOV DI,BX ;Move into DI.
INC DI ;Point to next storage.
INC DI
CMP DI,BUFFER_END ;Did we pass end of buffer?
JNZ CK_FULL_KBD ;If no, continue.
MOV DI,BUFFER_START ;Else, move to buffer start.
CK_FULL_KBD: CMP DI,BUFFER_HEAD ;Is the buffer full?
JZ CK_REPEAT ;If is, skip.
MOV [BX],AX ;Else, stuff buffer repeat.
MOV BUFFER_TAIL,DI ;Move the tail up one.
MOV CS:REPEAT_FLAG,TRUE ;Flag that we stuffed buffer.
CK_REPEAT: DEC CX ;If no, continue until done.
JNS NEXT_STUFF
FULL_KBD_EXIT: STI
POP DI ;Restore registers.
POP CX
POP BX
POP AX
INT_8_EXIT: POP DS
ASSUME DS:NOTHING
JMP DWORD PTR BIOS_INT_8 ;Give the old timer its turn.
FASTKEY_INT_8 ENDP
END_RESIDENT LABEL BYTE
;**********************************************;
; DISPOSABLE DATA
; ---------------
PATTERNS DW 0000000000000000B, 1000000000000000B, 1000000010000000B
DW 1000010000100000B, 1000100010001000B, 1001001001001000B
DW 1001001001001001B, 1001001010010101B, 1010101010101010B
DW 1101010101010101B, 1101101011011010B, 1101101101101101B
DW 1110111011101110B, 1111011110111101B, 1111111011111110B
DW 1111111111111110B
SYNTAX DB "Syntax: TYPEFAST [m][,n] | [/U] | [N]",CR,LF
DB "m = typematic rate (0 - 31); larger m = faster rate"
DB CR,LF
DB "n = initial delay (0 - 3); larger n = longer delay"
DB CR,LF
DB "default: m = 2; n = 3",CR,LF
DB "N = Normal",CR,LF
DB "/U = Uninstall",CR,LF,"$"
BAD_PARAMETER DB "Invalid parameter",CR,LF,LF,BELL,"$"
UNLOAD_MSG DB "TYPEFAST can't be uninstalled.",CR,LF,BELL
DB "Uninstall resident programs in reverse order.",CR,LF
DB "TYPEFAST "
INACTIVE_MSG DB "INACTIVE",CR,LF,LF,"$"
ALLOCATE_MSG DB "Memory allocation error",CR,LF,BELL,"$"
INSTALL_MSG DB "Installed",CR,LF,LF,"$"
UNINSTALL_MSG DB "Uninstalled",CR,LF,LF,"$"
;--------------------------------------------------------------------;
; Search memory for a copy of our code, to see if already installed. ;
;--------------------------------------------------------------------;
INITIALIZE PROC NEAR
ASSUME DS:_TEXT
CLD ;All string operations forward.
MOV BX,OFFSET START ;Point to start of code.
NOT BYTE PTR [BX] ;Change a byte so no false match
; with a disk cache copy.
MOV AX,CS ;Store our segment in AX.
MOV DX,AX ;Start at our segment.
NEXT_PARA: INC DX ;Next paragraph.
MOV ES,DX
CMP DX,AX ;Is it our segment?
JZ PARSE ;If yes, search is done.
MOV SI,BX ;Else, point to our signature.
MOV DI,BX ; and offset of possible match.
MOV CX,16 ;Check 16 bytes for match.
REP CMPSB
JNZ NEXT_PARA ;If no match, keep looking.
;-------------------------------------------------;
; Parse the command line for uninstall parameter. ;
;-------------------------------------------------;
PARSE: MOV DX,OFFSET SIGNATURE ;Display our signature.
CALL PRINT_STRING
MOV SI,81H ;Point to command line.
SEARCH_SWITCH: LODSB ;Get a byte.
CMP AL,CR ;Is it carriage return?
JZ PARAMETERS ;If yes, done here.
CMP AL,"/" ;Is there a switch character?
JNZ SEARCH_SWITCH ;If no, keep looking.
LODSB ;Else, get the switch character.
AND AL,5FH ;Capitalize.
CMP AL,"U" ;Is it uninstall?
JNZ PARAMETERS ;If no, done here.
JMP UNINSTALL ;Else, uninstall.
;--------------------------------------------------------;
; Parse command line for typematic and delay parameters. ;
;--------------------------------------------------------;
PARAMETERS: MOV SI,81H ;Point to command line.
FIND_PARA: LODSB
CMP AL,CR
JZ FOUND_PARA
CMP AL,SPACE
JBE FIND_PARA
FOUND_PARA: DEC SI
MOV AL,[SI]
AND AL,5FH
CMP AL,"N"
MOV AL,0
JZ CALC_PATTERN
CALL DECIMAL_INPUT ;Get requested typematic rate.
MOV AL,REPEAT_DEFAULT ;Assume no parameter.
JCXZ CALC_PATTERN ;If none, use default.
MOV AL,BL ;Else, rate in AL.
CMP BL,REPEAT_MAX ;Is it greater than max rate?
JA ERROR_EXIT ;If yes, exit with error msg.
CALC_PATTERN: MOV BL,AL
MOV CL,4
SHR BL,CL
XOR BH,BH
MOV ES:REPEAT_CNT,BX
AND AL,0FH
XOR AH,AH
SHL AX,1
PUSH SI
MOV SI,AX
ADD SI,OFFSET PATTERNS
LODSW
MOV ES:REPEAT,AX
POP SI
GET_DELAY: CALL DECIMAL_INPUT ;Get requested initial delay.
MOV AL,INIT_DEFAULT ;Assume no parameter.
JCXZ STORE_DELAY ;If none, use default.
MOV AL,BL ;Else, delay in AL.
CMP BL,INITIAL_MAX ;Is it greater than max delay?
JA ERROR_EXIT ;If yes, exit with error msg.
STORE_DELAY: MOV ES:INIT_DELAY,AL ;Else, store initial delay.
;-----------------------;
; Print active message. ;
;-----------------------;
CK_INSTALL: MOV ES:ACTIVE_FLAG,TRUE ;Flag as active.
MOV DX,OFFSET INACTIVE_MSG + 2 ;Display active msg.
CALL PRINT_STRING
MOV AX,ES ;Are we already installed?
MOV BX,CS
CMP AX,BX
JZ INSTALL ;If no, install.
XOR AL,AL ;Else, ERRORLEVEL of zero.
JMP SHORT EXIT ;Exit.
;-------------------------------------------------------------------;
; Exit. Return ERRORLEVEL code 0 if successful, 1 if unsuccessful. ;
;-------------------------------------------------------------------;
ERROR_EXIT: MOV DX,OFFSET BAD_PARAMETER ;Display error message.
MSG_EXIT: CALL PRINT_STRING
MOV AL,1 ;ERRORLEVEL = 1.
EXIT: PUSH AX ;Preserve ERRORLEVEL.
MOV DX,OFFSET SYNTAX ;Display syntax message.
CALL PRINT_STRING
POP AX ;Retrieve ERRORLEVEL.
MOV AH,4CH ;Terminate.
INT 21H
;--------------------------------;
; This is the install procedure. ;
;--------------------------------;
INSTALL: MOV AX,DS:[2CH] ;Get environment segment.
MOV ES,AX
MOV AH,49H ;Free up environment.
INT 21H
MOV DX,OFFSET ALLOCATE_MSG
JC MSG_EXIT ;If error, exit with message.
MOV AX,3509H ;Get keyboard interrupt.
INT 21H
MOV BIOS_INT_9[0],BX ;Save old interrupt.
MOV BIOS_INT_9[2],ES
MOV DX,OFFSET FASTKEY_INT_9 ;Install new interrupt.
MOV AX,2509H
INT 21H
MOV AX,3508H ;Get timer interrupt.
INT 21H
MOV BIOS_INT_8[0],BX ;Save old interrupt.
MOV BIOS_INT_8[2],ES
MOV DX,OFFSET FASTKEY_INT_8 ;Install new interrupt.
MOV AX,2508H
INT 21H
MOV DX,OFFSET INSTALL_MSG ;Display install message.
CALL PRINT_STRING
MOV DX,OFFSET SYNTAX ;Display syntax.
CALL PRINT_STRING
MOV DX,OFFSET END_RESIDENT ;Point to end of resident portion
ADD DX,15 ;Round up.
MOV CL,4
SHR DX,CL ;Convert to paragraphs.
MOV AX,3100H ;Return error code of zero.
INT 21H ;Terminate but stay resident.
;---------------------------------------------------;
; This subroutine uninstalls the resident TYPEFAST. ;
;---------------------------------------------------;
UNINSTALL: MOV ES:ACTIVE_FLAG,FALSE ;Flag as inactive.
MOV ES:TYPEMATIC,FALSE ;Turn off typematic.
MOV DX,OFFSET UNLOAD_MSG ;Error message if INT 9h changed.
MOV CX,ES
MOV BX,CS
CMP AX,BX ;Is segment vector same?
JZ UNINSTALL_END ;If yes, not installed; exit.
MOV AX,3509H ;Get keyboard interrupt.
INT 21H
CMP BX,OFFSET FASTKEY_INT_9 ;Has it been hooked by another?
JNZ UNINSTALL_END ;If yes, exit with error message.
MOV BX,ES
CMP BX,CX ;Is the segment vector same?
JNZ UNINSTALL_END ;If yes, exit with error message.
MOV AX,3508H ;Get timer interrupt.
INT 21H
CMP BX,OFFSET FASTKEY_INT_8 ;Has it been hooked by another?
JNZ UNINSTALL_END ;If yes, exit with error message.
MOV BX,ES
CMP BX,CX ;Is the segment vector same?
JNZ UNINSTALL_END ;If yes, exit with error message.
MOV AH,49H ;Return memory to system pool.
INT 21H
MOV DX,OFFSET ALLOCATE_MSG
JC UNINSTALL_END ;Display message if problem.
MOV DX,ES:BIOS_INT_9[0] ;Restore old INT 9.
MOV DS,ES:BIOS_INT_9[2]
MOV AX,2509H
INT 21H
MOV DX,ES:BIOS_INT_8[0] ;Restore old INT 8.
MOV DS,ES:BIOS_INT_8[2]
MOV AX,2508H
INT 21H
PUSH CS
POP DS ;Point to our data.
MOV DX,OFFSET UNINSTALL_MSG ;Display uninstall message.
UNINSTALL_END: JMP MSG_EXIT ;And exit.
INITIALIZE ENDP
;---------------------------------;
; INPUT ;
; SI points to parameter start. ;
; ;
; OUTPUT ;
; BL = number. ;
; CX = parameter length. ;
; BP preserved. ;
;---------------------------------;
DECIMAL_INPUT PROC NEAR
XOR BL,BL ;Start with zero as number.
XOR CX,CX ;Parameter length zero.
LEADING_WHITE: LODSB ;Get a byte.
CMP AL,CR ;Is it carriage return?
JZ ADJUST_DEC ;If yes, done here.
CMP AL,SPACE ;Is it leading white space?
JBE LEADING_WHITE ;If yes, parse off.
DECIMAL: DEC SI ;Adjust pointer.
NEXT_DECIMAL: LODSB ;Get a character.
CMP AL,CR ;Is it carriage return?
JZ ADJUST_DEC ;If yes, done here.
SUB AL,"0" ;ASCII to binary.
JC END_DECIMAL ;If not between 0 and 9, skip.
CMP AL,9
JA END_DECIMAL
XCHG AL,BL ;Swap old and new number.
MOV CL,10 ;Shift to left by multiplying
MUL CL ; last entry by ten.
JC DECIMAL_ERROR ;If carry, too big.
ADD BL,AL ;Add new number and store in BL.
JNC NEXT_DECIMAL ;If not carry, next number.
DECIMAL_ERROR: MOV BL,-1 ;Else, too big; return -1.
ADJUST_DEC: DEC SI ;Adjust pointer.
END_DECIMAL: RET
DECIMAL_INPUT ENDP
;--------------------------;
PRINT_STRING: MOV AH,9 ;Print string via DOS.
INT 21H
RET
_TEXT ENDS
END START